package com.zensun.common.utils.convert;

import cn.hutool.core.util.ObjectUtil;

import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.ToDoubleFunction;
import java.util.function.ToIntFunction;
import java.util.stream.Collectors;

/**
 * Stream流工具类
 *
 * @author gmk
 * @date 2020-11-17
 */
public class StreamUtils {
    /**
     * 过滤一个集合,获取一个新list
     * 如果集合为空或者是null,返回一个空ArrayList
     *
     * @param list      原list
     * @param predicate 过滤条件
     * @param <T>
     * @return 过滤后的list
     */
    public static <T> List<T> filter(Collection<T> list, Predicate<? super T> predicate) {
        if (ObjectUtil.isEmpty(list)) {
            return new ArrayList<>();
        }
        return list.stream().filter(predicate).collect(Collectors.toList());
    }

    /**
     * 将list集合以指定方式分组
     * 如果list为空或者是null,返回一个空HashMap
     *
     * @param list     元list
     * @param function 分组规则
     * @param <T>
     * @param <K>
     * @return 分组结果
     */
    public static <T, K> Map<K, List<T>> groupingBy(Collection<T> list, Function<? super T, ? extends K> function) {
        if (ObjectUtil.isEmpty(list)) {
            return new HashMap<>();
        }
        return list.stream().collect(Collectors.groupingBy(function));
    }

    /**
     * 将list集合筛选后
     * 以指定方式分组
     * 如果list为空或者是null,返回一个空HashMap
     *
     * @param list      原list
     * @param predicate 过滤条件
     * @param function  分组规则
     * @param <T>
     * @param <K>
     * @return 分组结果
     */
    public static <T, K> Map<K, List<T>> filterGroupingBy(Collection<T> list, Predicate<? super T> predicate, Function<? super T, ? extends K> function) {
        if (ObjectUtil.isEmpty(list)) {
            return new HashMap<>();
        }
        return list.stream().filter(predicate).collect(Collectors.groupingBy(function));
    }

    /**
     * 获取集合中最大值
     * 如果集合为空会抛出异常
     *
     * @param list 集合数据
     * @return 最大值
     * @throws Exception
     */
    public static Integer max(Collection<Integer> list) throws Exception {
        if (ObjectUtil.isEmpty(list)) {
            throw new NoSuchElementException("集合为空,不存在最大值");
        }
        return list.stream().max(Integer::compareTo).orElseThrow(() -> new Exception());
    }

    /**
     * 获取集合中对象某个属性的最大值
     * 如果集合为空会抛出异常
     *
     * @param list 集合数据
     * @return 最大值
     * @throws Exception
     */
    public static <T> Integer max(Collection<T> list, ToIntFunction<? super T> mapper) throws Exception {
        if (ObjectUtil.isEmpty(list)) {
            throw new NoSuchElementException("集合为空,不存在最大值");
        }
        return list.stream().mapToInt(mapper).max().orElseThrow(() -> new Exception());
    }

    /**
     * 获取集合中对象某个属性的最大值
     * 如果集合为空会抛出异常
     *
     * @param list 集合数据
     * @return 最大值
     * @throws Exception
     */
    public static <T> Double max(Collection<T> list, ToDoubleFunction<? super T> mapper) throws Exception {
        if (ObjectUtil.isEmpty(list)) {
            throw new NoSuchElementException("集合为空,不存在最大值");
        }
        return list.stream().mapToDouble(mapper).max().orElseThrow(() -> new Exception());
    }

    /**
     * 获取集合中最小值
     * 如果集合为空会抛出异常
     *
     * @param list 集合数据
     * @return 最小值
     * @throws Exception
     */
    public static Integer min(Collection<Integer> list) throws Exception {
        if (ObjectUtil.isEmpty(list)) {
            throw new NoSuchElementException("集合为空,不存在最小值");
        }
        return list.stream().min(Integer::compareTo).orElseThrow(() -> new Exception());
    }

    /**
     * 获取集合中对象某个属性的最小值
     * 如果集合为空会抛出异常
     *
     * @param list 集合数据
     * @return 最小值
     * @throws Exception
     */
    public static <T> Integer min(Collection<T> list, ToIntFunction<? super T> mapper) throws Exception {
        if (ObjectUtil.isEmpty(list)) {
            throw new NoSuchElementException("集合为空,不存在最小值");
        }
        return list.stream().mapToInt(mapper).min().orElseThrow(() -> new Exception());
    }

    /**
     * 获取集合中对象某个属性的最小值
     * 如果集合为空会抛出异常
     *
     * @param list 集合数据
     * @return 最小值
     * @throws Exception
     */
    public static <T> Double min(Collection<T> list, ToDoubleFunction<? super T> mapper) throws Exception {
        if (ObjectUtil.isEmpty(list)) {
            throw new NoSuchElementException("集合为空,不存在最小值");
        }
        return list.stream().mapToDouble(mapper).min().orElseThrow(() -> new Exception());
    }

    /**
     * 计算集合中数据的总和
     * 如果集合为空返回 0
     *
     * @param list   原集合
     * @param mapper
     * @param <T>
     * @return 总和
     */
    public static <T> Integer sum(Collection<T> list, ToIntFunction<? super T> mapper) {
        if (ObjectUtil.isEmpty(list)) {
            return 0;
        }
        return list.stream().mapToInt(mapper).sum();
    }

    /**
     * 计算集合中数据的总和
     * 如果集合为空返回 0.0
     *
     * @param list   原集合
     * @param mapper
     * @param <T>
     * @return 总和
     */
    public static <T> Double sum(Collection<T> list, ToDoubleFunction<? super T> mapper) {
        if (ObjectUtil.isEmpty(list)) {
            return 0.0;
        }
        return list.stream().mapToDouble(mapper).sum();
    }

    /**
     * 转换集合类型
     * 如果集合为空或者是null
     * 返回一个空集合
     *
     * @param list   原集合
     * @param mapper 转换规则
     * @param <T>
     * @param <R>
     * @return 转换后的集合
     */
    public static <T, R> List<R> map(Collection<T> list, Function<? super T, ? extends R> mapper) {
        if (ObjectUtil.isEmpty(list)) {
            return new ArrayList<>();
        }
        return list.stream().map(mapper).collect(Collectors.toList());
    }

    /**
     * 转换集合类型
     * 如果集合为空或者是null
     * 返回一个空HashSet集合
     *
     * @param list   原集合
     * @param mapper 转换规则
     * @param <T>
     * @param <R>
     * @return 转换后的集合
     */
    public static <T, R> Set<R> mapSet(Collection<T> list, Function<? super T, ? extends R> mapper) {
        if (ObjectUtil.isEmpty(list)) {
            return new HashSet<>();
        }
        return list.stream().map(mapper).collect(Collectors.toSet());
    }

    /**
     * 根据条件筛选过集合后进行
     * 转换集合类型
     * 如果集合为空或者是null
     * 返回一个空集合
     *
     * @param list   原集合
     * @param mapper 转换规则
     * @param <T>
     * @param <R>
     * @return 转换后的集合
     */
    public static <T, R> List<R> filterMap(Collection<T> list, Predicate<? super T> predicate, Function<? super T, ? extends R> mapper) {
        if (ObjectUtil.isEmpty(list)) {
            return new ArrayList<>();
        }
        return list.stream().filter(predicate).map(mapper).collect(Collectors.toList());
    }
}
